package com.hmdp.utils;

// 登录拦截器-----需要在配置类中 装载这个 拦截器

import cn.hutool.core.bean.BeanUtil;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.User;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.hmdp.utils.RedisConstants.LOGIN_USER_KEY;
import static com.hmdp.utils.RedisConstants.LOGIN_USER_TTL;

/** 登录拦截器，出登陆外的所有请求都要拦截，检查token，刷新token过期时间，放行
 * 校验session中的用户信息并将用户信息存入ThreadLocal中
 * //优化：使用redis存储用户信息，而不是session
 */
public class LoginIntercepter implements HandlerInterceptor {

    private StringRedisTemplate stringRedisTemplate;
    public LoginIntercepter(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }


    //拦截方法
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        // 1. 获取session中的用户信息
//        Object user = request.getSession().getAttribute("user");
//        if (user == null) {
//            // 2. 如果用户信息不存在，返回错误信息
//            response.setStatus(401);
//            return false;
//        }
//        // 3. 如果用户信息存在，将用户信息存入ThreadLocal中,UserHolder中已经封装好了ThreadLocal
//        UserDTO threaduser = BeanUtil.copyProperties(user, UserDTO.class); //属性复制
//        UserHolder.saveUser(threaduser);
//        // 4. 放行
//        return true;
        //TODO 优化：使用redis存储用户对象，而不是session，token携带在请求头中的Authorization字段中
        // redis取出 用户对象
        // 1. 获取请求头中的token
        String token = request.getHeader("authorization");
        if (token == null) {
            // 2. 如果token不存在，返回错误信息
            response.setStatus(401);
            return false;  // 不放行
        }
        //TODO  从redis中根据token（key）取出用户对象
        // 2. 取出，entries()取出所有的key-value对，而get只能取出一个value
        Map<Object,Object> redisuser = stringRedisTemplate.opsForHash().entries(LOGIN_USER_KEY+token);
        if (redisuser.isEmpty()) {
            // 3. 如果用户信息不存在，返回错误信息
            response.setStatus(401);
            return false;// 不放行
        }
        // 4. 将用户对象存入ThreadLocal中，方便后续使用
        UserDTO threaduser = BeanUtil.fillBeanWithMap(redisuser, new UserDTO(), false); //转换为UserDTO对象
        UserHolder.saveUser(threaduser);

        //重点！！每次拦截通过后，校验通过后，都要刷新token的过期时间，以保证在用户使用期间一直保持登录状态
        /**
         * 特殊---这里的stringRedisTemplate对象无法注入，需要通过配置类中创建拦截器对象时，手动传入
         */
        stringRedisTemplate.expire(LOGIN_USER_KEY+token, LOGIN_USER_TTL, TimeUnit.MINUTES);

        // 5. 放行
        return true;

        //TODO  最终版本：
        //LoginIntercepter.java只需要判断ThreadLocal中是否存在user对象是否存在即可（只判断权限即可
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 移除ThreadLocal中的用户信息
        UserHolder.removeUser();
    }

}
